import { FocusEvent } from 'react'
import dayjs from 'dayjs'
import BigNumber from 'bignumber.js'
import copy from 'copy-to-clipboard'
import { FormInstance, message, Modal } from 'antd'

import { STORAGE_KEY_TOKEN, STORAGE_KEY_USER_INFU } from '@/consts/consts'

/**
 * 以刷新方式跳转登录页（清内存，避免干扰）
 * - TODO: 暂时跳转旧登录页，后续可能要跳转新登录页
 */
export const refreshToLoginPage = () => {
  localStorage.setItem(STORAGE_KEY_TOKEN, '')
  localStorage.setItem(STORAGE_KEY_USER_INFU, '')
  if (import.meta.env.DEV) {
    Modal.confirm({
      width: 420,
      type: 'error',
      title: '登录异常，请重新登录 @DEV',
      content: `登录成功后需手动存储登录态及用户信息至localStorage，相关字段为：x-auth-token、userInfo`,
      cancelText: '刷新页面',
      okText: '打开登录页',
      onOk: async () => {
        open(`http://dev.${$APP === 'OMS' ? 'oms' : 'tms'}.elinkhub.com/#/admin/user/login`)
        throw new Error()
      },
      onCancel: async () => {
        location.reload()
        throw new Error()
      },
    })
  } else {
    const redirect = `${location.pathname}${location.search}${location.hash}`
    location.replace(`${location.origin}/#/admin/user/login?newFba=1&redirect=${encodeURIComponent(redirect)}`)
  }
}

/**
 * 邮箱验证（验证通过则返回 true）
 */
export const emailValidate = Object.assign(
  (value: string | null | undefined, ignoreSpaces?: boolean): boolean => {
    value = `${value || ''}`
    if (ignoreSpaces) value = value.replace(/\s+/g, '')
    return !!value && emailValidate.emailReg.test(value)
  },
  {
    /** 邮箱验证正则对象 @link https://emailRegex.com */
    emailReg:
      // eslint-disable-next-line no-useless-escape
      /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
  },
)

/**
 * 附件校验（校验不通过则返回提示语）
 */
export const fileValidate = Object.assign(
  (
    file: File | File[],
    {
      accept,
      max,
    }: {
      /** 格式限定，统一使用后缀名 @example `.xls,.xlsx,.xlsm` */
      accept?: string
      /** 大小限定，单位为 MB @default 1 */
      max?: number
    },
  ): string | undefined => {
    if (typeof max !== 'number') max = 1
    max = max || 1

    const fileList = [file].flat(1)
    const acceptList = accept?.split(',').map(v => v.trim().toLowerCase()) || []
    for (const { name, size } of fileList) {
      if (acceptList?.length) {
        if (!acceptList.some(v => name.toLowerCase().endsWith(v))) {
          return `格式仅限定为${accept}`
        }
      }
      if (size > max * 1024 * 1024) {
        return `单个附件大小不能超过${max}MB`
      }
    }
  },
  {
    /** 通用的单文件大小上限(MB) */
    MAX: 50 as const,
    /** 图片格式 */
    IMG_ACCEPT: `.jpg,.jpeg,.png,.bmp,.gif,.tif,.tiff,.webp` as const,
    /** excel 格式 */
    EXCEL_ACCEPT: `.xls,.xlsx,.xlsm,.xlt,.xltx,.xltm` as const,
    /** word 格式 */
    WORD_ACCEPT: `.doc,.docx,.dot,.dotx,dotm,.docm` as const,
    /** pdf 格式 */
    PDF_ACCEPT: `.pdf,.pdfa,.xfdf,.fdf` as const,
    /** zip 格式 */
    ZIP_ACCEPT: `.zip,.rar,.7z,.tar,.gz,.bz2,.xz` as const,
    /** 图片格式判断 */
    isImgUrl: (url: string | null | undefined): boolean => {
      const lowerCasePath = `${url || ''}`.split(/\?|#/)[0].trim().toLowerCase()
      const acceptList = fileValidate.IMG_ACCEPT.split(',').map(v => v.trim().toLowerCase())
      return acceptList.some(d => lowerCasePath.endsWith(d))
    },
  },
)

/**
 * Form 表单失焦自动 trim
 */
export const formAutoTrimOnBlur = (opts: {
  /** onBlur 事件对象 */
  event: FocusEvent<HTMLFormElement, Element>
  /** 表单实例 */
  form: FormInstance
  /** 包含字段，默认为全部可输入字段 --- 嵌套字段请用_分隔 */
  includeField?: string[]
  /** 排除字段 --- 嵌套字段请用_分隔 */
  excludeField?: string[]
  /** 触发回调 */
  onTrim?: () => void
}) => {
  const { event, form, includeField, excludeField, onTrim } = opts
  const el = event.target

  if (el instanceof HTMLElement === false) return
  if (el.type !== 'text' && el.type !== 'textarea') return

  const id = el.id
  const name = id.split('_').map(v => (/\d+/.test(v) ? +v : v)) // 列表索引处理

  if (!id) return
  if (includeField && !includeField.includes(id)) return
  if (excludeField && excludeField.includes(id)) return

  const v1 = form.getFieldValue(name)
  if (typeof v1 !== 'string') return
  const v2 = v1.trim()
  if (v1 === v2) return
  form.setFieldValue(name, v2)
  form.validateFields([name])
  onTrim?.()
}

/** 统一 Select filterOption  */
export const selectFilterOption = (
  inputValue: string,
  option?: { value?: string | number | null; label?: React.ReactNode; title?: string },
): boolean => {
  inputValue = inputValue.trim().toLocaleLowerCase()

  let optLabel = ''
  // 优先 label
  if (typeof option?.label === 'string' || typeof option?.label === 'number') {
    if (!Number.isNaN(option.label)) {
      optLabel = `${option.label}`.toLocaleLowerCase()
    }
  }
  // 其次 title
  else if (typeof option?.title === 'string' || typeof option?.title === 'number') {
    if (!Number.isNaN(option.title)) {
      optLabel = `${option.title}`.toLocaleLowerCase()
    }
  }

  if (optLabel) return optLabel.includes(inputValue)
  return `${option?.value ?? ''}`.toLocaleLowerCase().includes(inputValue)
}

/**
 * 千分位格式化
 * @param opts.placeholder 默认 '--'
 * @param opts.precision 精度，默认 2
 */
export const toThousands = (
  val: BigNumber.Value | null | undefined,
  opts?: {
    /** 默认 '--' */
    placeholder?: string
    /** 精度，默认 2，传 null 表示不处理 */
    precision?: number | null
  },
): string => {
  let { placeholder, precision } = opts || {}
  placeholder = placeholder ?? '--'
  precision = precision === null ? undefined : (precision ?? 2)

  if (val === '' || val == null) {
    return placeholder
  }

  const v = new BigNumber(val).toFormat(precision)
  return v === 'NaN' ? placeholder : v
}

/** 禁用未来日期 */
export const disableFutureDate = (curr: dayjs.Dayjs): boolean => curr.endOf('day') > dayjs().endOf('day')
/** 禁用未来时间 */
export const disableFutureTime = (curr: dayjs.Dayjs) => {
  const now = dayjs()
  if (curr.isSame(now, 'day')) {
    return {
      disabledHours: () => Array.from({ length: 24 }, (_, i) => i).filter(hour => hour > now.hour()),
      disabledMinutes: (selectedHour: number) =>
        selectedHour === now.hour()
          ? Array.from({ length: 60 }, (_, i) => i).filter(minute => minute > now.minute())
          : [],
      disabledSeconds: (selectedHour: number, selectedMinute: number) =>
        selectedHour === now.hour() && selectedMinute === now.minute()
          ? Array.from({ length: 60 }, (_, i) => i).filter(second => second > now.second())
          : [],
    }
  }
  return {}
}

/** 链接校验 */
export const isValidURL = (url: string): boolean => {
  const regex = /^(https?:\/\/)?([a-z0-9-]+\.)+[a-z]{2,6}(\/[^\s]*)?$/i
  return regex.test(url)
}

/** 给头像链接增加裁切参数 */
export const addAvatarOSSParams = <T extends string | null | undefined>(url: T, size = 100): T => {
  if (url?.includes('.aliyuncs.com/') && !/\?|#/.test(url)) {
    return `${url}?x-oss-process=image/resize,l_${size}` as T
  }
  return url
}

/** xdxh */
export const dhFormat = (hour: string | number | null | undefined): string => {
  const val = +`${hour ?? '--'}`
  if (Number.isNaN(val)) return ''
  const days = Math.floor(val / 24)
  const remainingHours = val % 24
  let result = ''
  if (days > 0) result += `${days}d`
  if (remainingHours > 0 || days === 0) result += `${remainingHours}h`
  return result
}

/**
 * 复制
 * @example
 * <Button
 *   type="text"
 *   icon={<CopyOutlined />}
 *   disabled={!value}
 *   onClick={() => handleCopy(value)}
 * />
 */
export const handleCopy = (text: string | number | null | undefined, opts?: { isEn?: boolean }) => {
  let txt = ''
  if (typeof text === 'string') txt = text
  else if (typeof text === 'number' && !Number.isNaN(text)) txt = `${text}`
  if (!txt) {
    message.error(opts?.isEn ? 'Copy failed' : '复制失败', 1)
    return
  }
  copy(txt)
  message.success(opts?.isEn ? 'Copy successful' : '复制成功', 1)
}
